/**
 * @FilePath     : /src/lgmg_robots/agv_navigation/agv_navigate/agvNavigate/helpSrc/report_run_data.cpp
 * @Description  : 该文件实现了ReportRunData类，用于管理和报告导航和轨迹数据。
 *                 主要功能包括初始化和清理资源、设置和获取路径属性、设置导航和轨迹类型。
 *                 提供了对导航模式和轨迹类型的自动模式支持和更新。
 * @Author       : xiujun.yang
 * @Version      : 1.0.0
 * @LastEditors  : haibo haibo.yang@lgmgim.cn
 * @LastEditTime : 2024-12-19 18:53:49
 * @Copyright (c) 2024 by 临工智能信息科技有限公司, All Rights Reserved. 
**/ 
#include "report_run_data.h"
constexpr const char PARAM_NAV_TYPE[] = "agv_navigation_type";
constexpr const char PARAM_TRAJ_TYPE[] = "traj_type";

/**
 * @brief ReportRunData类的构造函数
 *
 * 初始化ReportRunData对象，设置初始化状态、自动模式、节点句柄和位字段。
 * 同时调用InitGuideTypeValue和InitTrajTypeValue方法初始化相应的值。
 */
ReportRunData::ReportRunData() 
               : initialized_(false),
               auto_mode_(false),
               bits_(0) 
{
   InitGuideTypeValue();
   InitTrajTypeValue();
}

/**
 * @brief 析构函数，用于清理资源
 *
 * 在析构函数中，首先解锁互斥锁，然后中断工作线程，并等待其结束。
 */
ReportRunData::~ReportRunData() 
{
   quit_mutex_.unlock();
   worker_thread_->interrupt();
   worker_thread_->join();
}

/**
 * @brief 初始化ReportRunData对象
 *
 * 初始化ReportRunData对象，设置必要的参数并启动工作线程。
 *
 * @param nh 指向rclcpp::Node对象的指针，用于ROS通信
 *
 * @return 初始化成功返回true，否则返回false
 */
bool ReportRunData::Init() 
{
   if (initialized_) {
      return true;
   }
  
   quit_mutex_.lock();
   worker_thread_.reset(new boost::thread(boost::bind(&ReportRunData::SetAreaCycle, this)));
   initialized_ = true;
   return initialized_;
}

/**
 * @brief 设置自动模式
 *
 * 设置自动模式。
 *
 * @param enable 布尔值，true表示启用自动模式，false表示禁用自动模式
 *
 * @return 如果设置成功，则返回true；如果设置失败（例如未初始化），则返回false
 */
bool ReportRunData::SetAutoMode(bool enable) 
{
   if (!initialized_) {
      DEBUG_OUT("Error: Current laser detect set auto mode failed: not initialized");
      return false;
   }
   if (auto_mode_ != enable) {
      auto_mode_ = enable;
      DEBUG_OUT("OK: Current laser detect change mode OK; autoMode=" << auto_mode_);
   }
   return true;
}

/**
 * @brief 设置区域循环
 *
 * 尝试获取互斥锁quit_mutex_，若无法立即获取，则在自动模式下调用ClientSetGuideType和ClientSetTrajType函数。
 *
 * 若在25毫秒内成功获取到quit_mutex_的锁，则不进行任何操作。
 */
void ReportRunData::SetAreaCycle() 
{
   while (!quit_mutex_.try_lock_for(std::chrono::milliseconds(25))) {
      if (auto_mode_) {
         ClientSetGuideType();
         ClientSetTrajType();
      }
   }
}

////////////////////////////set map property///////////////////////////
/**
 * @brief 设置路径数据的位属性
 *
 * 设置路径数据的位属性，并打印相关信息。
 *
 * @param bits 位属性
 */
void ReportRunData::SetPathBitsProperty(const uint16_t& bits) 
{
   path_data_.bits = bits;
   DEBUG_OUT("SetPathBitsProperty: bits=" << path_data_.bits
                                          << ", scenes=" << path_data_.scenes 
                                          << ", word1=" << path_data_.word1 
                                          << ", word2=" << path_data_.word2);
}

/**
 * @brief 设置路径点字段属性
 *
 * 设置路径点字段属性，并打印出相关调试信息。
 *
 * @param word1 第一个字段
 * @param word2 第二个字段
 */
void ReportRunData::SetPathPointWordsProperty(const int& word1, const int& word2) 
{
   path_data_.word1 = word1;
   path_data_.word2 = word2;
   DEBUG_OUT("SetPathPointWordsProperty: bits=" << path_data_.bits
                                                << ", scenes=" << path_data_.scenes 
                                                << ", word1=" << path_data_.word1 
                                                << ", word2=" << path_data_.word2);
}

/**
 * @brief 设置路径字段属性
 *
 * 设置路径字段属性，包含两个字段word1和word2。
 *
 * @param word1 第一个路径字段
 * @param word2 第二个路径字段
 */
void ReportRunData::SetPathWordsProperty(const int& word1, const int& word2) 
{
   path_data_.path_word1 = word1;
   path_data_.path_word2 = word2;
   DEBUG_OUT("SetPathWordsProperty: word1=" << path_data_.path_word1 
                                             << ", word2=" << path_data_.path_word2);
}

/**
 * @brief 设置路径场景属性
 *
 * 将传入的场景字符串赋值给路径数据的场景属性，并输出调试信息。
 *
 * @param scenes 场景字符串
 */
void ReportRunData::SetPathScenesProperty(const std::string& scenes) 
{
   path_data_.scenes = scenes;
   DEBUG_OUT("SetPathScenesProperty: bits=" << path_data_.bits
                                             << ", scenes=" << path_data_.scenes 
                                             << ", word1=" << path_data_.word1 
                                             << ", word2=" << path_data_.word2);
}

/**
 * @brief 获取路径属性
 *
 * 获取当前对象中的路径属性数据。
 *
 * @return 返回路径属性数据，类型为RunPathProperty。
 */
RunPathProperty ReportRunData::GetPathProperty() 
{
   return path_data_;
}

/**
 * @brief 清空报告运行数据
 *
 * 该函数用于清空ReportRunData对象中存储的路径数据。
 */
void ReportRunData::Clear() 
{
   path_data_.Clear();
}
////////////////////////set guide type//////////////////////
/**
 * @brief 设置当前导航模式
 *
 * 设置当前导航模式，并标记导航模式已更新。
 *
 * @param mode 要设置的导航模式（USHORT类型）
 */
void ReportRunData::SetCurGuideMode(USHORT mode) 
{
   update_guide_mode_ = true;
   current_guide_mode_ = mode;
   DEBUG_OUT("Ready to set navigation mode, currentGuideMode=" << current_guide_mode_);
}

/**
 * @brief 初始化导航模式
 *
 * 该函数用于初始化导航模式，将更新导航模式标志位设置为false，并将当前导航模式设置为0。
 */
void ReportRunData::InitGuideTypeValue() 
{
   update_guide_mode_ = false;
   current_guide_mode_ = 0;
}

/**
 * @brief 设置客户端的导航模式
 *
 * 设置客户端的导航模式，如果初始化失败或者不需要更新导航模式，则返回true。
 * 如果需要更新导航模式，并且ROS节点句柄有效，则更新ROS参数中的导航类型为当前导航模式。
 *
 * @return 设置成功返回true，否则返回false。
 */
bool ReportRunData::ClientSetGuideType() 
{
   if (!initialized_) {
     DEBUG_OUT("Error: OpeLaserDetect not initialized; client ClientSetGuideType");
     return false;
   }

   if (!update_guide_mode_) {
     return true;
   }

   
   if (SharedParamsInterface::setParam("AGVParam", "agv_navigation_type", current_guide_mode_)) {
      DEBUG_OUT("Set param: guide mode, current_mode " << current_guide_mode_ << " success.");
   } else {
      DEBUG_OUT("Set param: guide mode, current_mode " << current_guide_mode_ << " failed.");
   }

   update_guide_mode_ = false;
   return true;
}
/////////////////////////////set traj type////////////////////////////////
// set traj type  static param
// m_pTraj->m_nType == SPIN_TRAJ
/**
 * @brief 设置当前轨迹类型
 *
 * 设置当前轨迹类型，并标记需要更新轨迹类型。
 *
 * @param type 轨迹类型，整型
 */
void ReportRunData::SetCurTrajType(int type) 
{
   update_traj_type_ = true;
   current_traj_type_ = type;
   DEBUG_OUT("Ready to set trajectory type, current_traj type=" << current_traj_type_);
}

/**
 * @brief 初始化轨迹类型值
 *
 * 初始化轨迹类型相关成员变量，将update_traj_type_设置为false，current_traj_type_设置为Traj_Line。
 */
void ReportRunData::InitTrajTypeValue() 
{
   update_traj_type_ = false;
   current_traj_type_ = Traj_Line;
}

/**
 * @brief 设置轨迹类型
 *
 * 此函数用于设置轨迹类型。
 *
 * @return 如果成功设置轨迹类型，则返回true；否则返回false。
 */
bool ReportRunData::ClientSetTrajType() 
{
   if (!initialized_) {
      DEBUG_OUT("Error: OpeLaserDetect not initialized; client ClientSetTrajType");
      return false;
   }

   if (!update_traj_type_) {
      return true;
   }
    
   if(SharedParamsInterface::setParam("AGVParam", "traj_type", current_traj_type_)) {
      DEBUG_OUT("Set param: trajectory type " << current_traj_type_ << " success.");
   } else {
      DEBUG_OUT("Set param: trajectory type " << current_traj_type_ << " failed.");
   }
    
   update_traj_type_ = false;
   return true;
}